#ifndef PIECE_H
#define PIECE_H

#include "Base.h"
#include "Constants.h"

class Piece {
public:

    Piece() : _size(0), _color(RED), _localPositions(NULL), _transformedPositions(NULL), _translationMatrix(), _rotationMatrix() {
    };

    Piece(const int size, const Colors color, const Point3f* positions)
    : _size(size), _color(color), _translationMatrix(), _rotationMatrix() {
        _localPositions = (Point3f*) malloc(size*sizeof(Point3f));
        _transformedPositions = (Point3f*) malloc(size*sizeof(Point3f));
        
        for(int i = 0; i < size; ++i) {
            int x = positions[i].x(), y = positions[i].y(), z = positions[i].z();
            _localPositions[i] = Point3f(x, y, z);
            _transformedPositions[i] = Point3f(x, y, z);
        }
    };

    int getSize() {
        return _size;
    };

    Colors getColor() {
        return _color;
    };

    void setToStartPosition(int x, int y, int z) {
        _translationMatrix = _translationMatrix.translation(x, y, z) * _translationMatrix;
    };
    
    Point3f* transformPositions(Matrix4f matrix, Operation op) {
        Point3f* positions = NULL;
        Matrix4f tmp;
        
        switch(op) {
            case ROTATE:
                tmp = _rotationMatrix;
                _rotationMatrix = matrix * _rotationMatrix;
                positions = getTransformedPositions();
                _rotationMatrix = tmp;
                break;
            case MOVE:
                tmp = _translationMatrix;
                _translationMatrix = matrix * _translationMatrix;
                positions = getTransformedPositions();
                _translationMatrix = tmp;
                break;
            default:
                break;
        }
        
        return positions;
    }

    Point3f* getTransformedPositions() {

        for (int i = 0; i < _size; ++i) {
            Point3f point = _rotationMatrix * _localPositions[i];
            _transformedPositions[i] = _translationMatrix * Point3f(round(point.x()), round(point.y()), round(point.z()));
        }

        return _transformedPositions;
    };
    
    
    bool comparePositions(Point3f* positions, int size) {
        if(size != _size)
            return false;
        else {
            getTransformedPositions();
            for(int i = 0; i < size; ++i) {
                if(!(positions[i] == _transformedPositions[i])) {
                    return false;
                }
            }
            
            return true;
        }
        
    };
    
    void rotate(Axis a, Orientation o) {
        char axis;

        switch (a) {
            case X:
                axis = 'X';
                break;
            case Y:
                axis = 'Y';
                break;
            default:
                axis = 'Z';
                break;
        }

        _rotationMatrix = _rotationMatrix.rotation((M_PI / 2.0) * o, axis) * _rotationMatrix;
    };

    void move(Axis a, Orientation o) {
        Matrix4f translationMatrix;
        
        switch (a) {
            case X:
                translationMatrix = translationMatrix.translation(1 * o, 0, 0);
                break;
            case Y:
                translationMatrix = translationMatrix.translation(0, 1 * o, 0);
                break;
            case Z:
                translationMatrix = translationMatrix.translation(0, 0, 1 * o);
                break;
            default:
                break;
        }
        
        _translationMatrix = translationMatrix * _translationMatrix;
    };

private:

    int _size;
    Colors _color;
    Matrix4f _translationMatrix;
    Matrix4f _rotationMatrix;
    Point3f* _localPositions;
    Point3f* _transformedPositions;

};

#endif